package com.axonactive.yolo.controller;

import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.axonactive.yolo.domain.SubscribedFlight;
import com.axonactive.yolo.domain.User;
import com.axonactive.yolo.domain.UserEmail;
import com.axonactive.yolo.dto.Flight;
import com.axonactive.yolo.dto.LoginParameters;
import com.axonactive.yolo.dto.Parameters;
import com.axonactive.yolo.dto.ParametersFilter;
import com.axonactive.yolo.dto.ResetPasswordParameters;
import com.axonactive.yolo.dto.ResetPasswordRequestParameters;
import com.axonactive.yolo.dto.SignupParameters;
import com.axonactive.yolo.dto.UserParameters;
import com.axonactive.yolo.exception.UserEmailNotFoundException;
import com.axonactive.yolo.exception.UserNotFoundException;
import com.axonactive.yolo.service.interfaces.EmailService;
import com.axonactive.yolo.service.interfaces.SubscribedFlightService;
import com.axonactive.yolo.service.interfaces.TaskService;
import com.axonactive.yolo.service.interfaces.UserEmailService;
import com.axonactive.yolo.service.interfaces.UserService;
import com.axonactive.yolo.util.EncryptDecrypt;
import com.axonactive.yolo.util.Utils;
import com.axonactive.yolo.util.session.SessionHelper;
import com.axonactive.yolo.validation.LoginValidator;
import com.axonactive.yolo.validation.ResetPasswordRequestValidator;
import com.axonactive.yolo.validation.ResetPasswordValidator;
import com.axonactive.yolo.validation.SignupValidator;
import com.axonactive.yolo.validation.UserProfileValidator;

@Controller
@RequestMapping(value = "/account")
@PropertySource("classpath:messages.properties")
public class UserController {

	private static final String DEFAULT_PASSWORD = "";
	private static final String PROPERTY_PRODUCT_NAME = "product.name";
	private static final String PROPERTY_EMAIL_HAS_SEND = "email.has.send";
	private static final String PROPERTY_EMAIL_HASNT_SEND = "email.hasnt.send";
	private static final String PROPERTY_REQUEST_NOT_ACCEPTED = "reset.password.not.accepted";
	private static final String PROPERTY_REQUEST_ACCEPTED = "reset.password.accepted";
	private static final String PROPERTY_USER_NOT_FOUND = "user.not.found";
	private static final String PROPERTY_SEND_EMAIL_SUCCESS = "send.email.success";
	// private static final String PROPERTY_LOGIN_SUCCESS = "log.in.success";
	// private static final String PROPERTY_LOGOUT_SUCCESS = "log.out.success";
	private static final String PROPERTY_EMAIL_HAS_SEND_PARAM = "email.has.send.param";
	private static final String PROPERTY_LINK_INCORRECT_OR_EXPIRED = "link.incorrect";
	private static final String PROPERTY_PASSWORD_RESET_TIME = "password.reset.time";
	private static final String PROPERTY_ACTIVATION_EXPIRED = "activation.expired.time";
//	private static final String PROPERTY_EMAIL_RESET_PASSWORD_SUBJECT = "email.reset.password.subject";
//	private static final String PROPERTY_EMAIL_RESET_PASSWORD_SUBJECT_SUCCESS = "email.reset.password.subject.success";
	private static final String PROPERTY_CREATE_ACCOUNT_SUCCESS = "create.account.success";
	private static final String PROPERTY_EMAIL_ACTIVED_PARAM = "email.activated.param";
	private static final String PROPERTY_EMAIL_DIDNT_ACTIVE = "email.didnt.active";
	private static final String PROPERTY_EMAIL_DIDNT_RECEIVE = "email.didnt.receive";
//	private static final String PROPERTY_EMAIL_ACTIVATION = "email.activation";
	private static final String PROPERTY_UPDATE_PROFILE_SUCCESS = "update.profile.success";

	@Resource
	private Environment env;

	@Autowired
	private SubscribedFlightService subcribedFlightService;

	@Autowired
	private UserService userService;

	@Autowired
	private UserEmailService userEmailService;

	@Autowired
	EmailService emailService;

	@Autowired
	ServletContext servletContext;

	@Autowired
	SignupValidator signupValidator;

	@Autowired
	LoginValidator loginValidator;

	@Autowired
	UserProfileValidator userProfileValidator;

	@Autowired
	ResetPasswordRequestValidator resetPasswordRequestValidator;
	
	@Autowired
	ResetPasswordValidator resetPasswordValidator;

	@Autowired
	private TaskService taskService;

	@Autowired
	private FlightController flightController;

	@InitBinder("signupParameters")
	private void signUpValidator(WebDataBinder binder) {
		binder.setValidator(signupValidator);
	}

	@InitBinder("loginParameters")
	private void loginValidator(WebDataBinder binder) {
		binder.setValidator(loginValidator);
	}

	@InitBinder("userParameters")
	private void userProfileValidator(WebDataBinder binder) {
		binder.setValidator(userProfileValidator);
	}

	@InitBinder("resetPasswordRequestParameters")
	private void resetPasswordRequestValidator(WebDataBinder binder) {
		binder.setValidator(resetPasswordRequestValidator);
	}
	
	@InitBinder("resetPasswordParameters")
	private void resetPasswordValidator(WebDataBinder binder) {
		binder.setValidator(resetPasswordValidator);
	}

	Logger LOGGER = Logger.getLogger(UserController.class);

	@RequestMapping(value = { "/login" }, method = RequestMethod.GET)
	public ModelAndView getLogin(
			@RequestParam(value = "userEmailID", required = false) String userEmailID) {
		return new ModelAndView();
	}

	@RequestMapping(value = { "/login" }, method = RequestMethod.POST)
	public ModelAndView postLogin(
			@ModelAttribute @Valid LoginParameters loginParams,
			BindingResult result, RedirectAttributes redirectAttribute,
			HttpSession session) throws IOException {
		if (result.hasErrors()) {
			ModelAndView mavError = new ModelAndView("account/login",
					"userEmail", loginParams.getUserEmail());
			LOGGER.error(result.toString());
			return mavError;
		} else {
			UserEmail userEmail = userEmailService
					.findByEmailString(loginParams.getUserEmail());

			// check activation status
			if (!userEmail.isActive()) {
				ModelAndView mav2 = new ModelAndView(
						"redirect:/account/activation_error.html");
				mav2.addObject("user_email", userEmail.getEmail());
				SessionHelper.setSaveUserEmailId(session, userEmail.getId());
				return mav2;
			}

			// save session
			SessionHelper.setUserEmail(session, userEmail);
			LOGGER.info(SessionHelper.isLoggedIn(session));

			User user = userEmail.getUser();
			SessionHelper.setCurrencyCode(session, user.getCurrency());

			// increase login_count
			try {
				user.setLoginCount(user.getLoginCount() + 1);
				userService.update(user);
			} catch (UserNotFoundException e) {
				LOGGER.info("User Not Found", e);
			}
			if (SessionHelper.isTransferFlagSet(session)) {
				SessionHelper.removeTransferFlag(session);
				LOGGER.info("isTransferFlagSet IN");
				Parameters param = SessionHelper.getSaveParameters(session);
				boolean isSuccess = flightController
						.createNewTaskFromSearchCriteria(param, session);
				ParametersFilter paramFilter = SessionHelper
						.getSaveParametersFilter(session);
				SessionHelper.setCreateQuickTaskResult(session, isSuccess);
				SessionHelper.removeTempFlight(session);
				SessionHelper.setLoginBackToSearchResult(session, "logined");
				return flightController.retainingValue(null, user.getId(),
						SessionHelper.getFlights(session), param, paramFilter,
						SessionHelper.getAirlinesNameList(session), session,
						redirectAttribute);
			} else if (SessionHelper.getTempFlight(session) != null) {
				Flight flight = SessionHelper.getTempFlight(session);
				Parameters param = SessionHelper.getSaveParameters(session);
				ParametersFilter paramFilter = SessionHelper
						.getSaveParametersFilter(session);

				SubscribedFlight subcribedFlight = subcribedFlightService
						.formatFlight(user.getId(), flight, param);

				SessionHelper.removeTempFlight(session);
				SessionHelper.setLoginBackToSearchResult(session, "logined");
				return flightController.retainingValue(subcribedFlight,
						user.getId(), SessionHelper.getFlights(session), param,
						paramFilter,
						SessionHelper.getAirlinesNameList(session), session,
						redirectAttribute);
			} else if (SessionHelper.isGoBackSubscribe(session)) {
				SessionHelper.removeGoBackSubscribe(session);
				return new ModelAndView("redirect:/subscribe/list.html");
			} else if (SessionHelper.isGoBackNoty(session)) {
				SessionHelper.removeGoBackNoty(session);
				return new ModelAndView(
						"redirect:/account/notification-center.html");
			} else if (SessionHelper.isGoBackTaskpage(session)) {
				SessionHelper.removeGoBackTaskpage(session);
				return new ModelAndView("redirect:/task/list.html");
			} else {
				ModelAndView _mav = new ModelAndView(
						"redirect:/flight/search.html");
				return _mav;
			}
		}
	}

	@RequestMapping(value = { "/logout" }, method = RequestMethod.GET)
	public ModelAndView getLogout(HttpSession session,
			RedirectAttributes redirectAttributes) {
		SessionHelper.removeUserEmail(session);
		SessionHelper.removeCurrencyCode(session);
		ModelAndView mav = new ModelAndView("redirect:/flight/search.html");
		return mav;
	}

	@RequestMapping(value = { "/profile" }, method = RequestMethod.GET)
	public ModelAndView getProfile(HttpSession session) {

		ModelAndView mav = new ModelAndView("account/profile");
		User user = new User();

		if (SessionHelper.isLoggedIn(session)) {
			int userId = SessionHelper.getUserId(session);
			user = userService.findById(userId);
			user.setPassword(DEFAULT_PASSWORD);
			SessionHelper.setSaveUserId(session, user.getId());
			SessionHelper.removeCurrencyCode(session);
			SessionHelper.setCurrencyCode(session, user.getCurrency());

			UserParameters userParams = new UserParameters();

			userParams.setUserId(userId);
			userParams.setCurrentPassword(DEFAULT_PASSWORD);
			userParams.setDefaultPassword(DEFAULT_PASSWORD);
			userParams.setTemporaryPassword(user.getPassword()); // in md5
			userParams.setFirstName(user.getFirstName() == null ? "" : user
					.getFirstName());
			userParams.setLastName(user.getLastName() == null ? "" : user
					.getLastName());
			userParams.setGender("" + user.getGender());
			userParams.setDateOfBirth(user.getDateOfBirth() == null ? ""
					: user.getDateOfBirth()
							.toString()
							.substring(
									0,
									user.getDateOfBirth().toString()
											.indexOf(" ")));
			userParams.setPhone(user.getPhone() == null ? "" : user.getPhone());
			String saveEmailPrimary = userService.getPrimaryEmail(userId);
			List<String> saveAlreadyAddedEmailSecondary = (List<String>) userService
					.findAllEmailByUserIdExceptPrimaryEmail(userId);
			userParams.setPrimaryEmail(saveEmailPrimary);
			userParams
					.setAlreadyAddedEmailSecondary(saveAlreadyAddedEmailSecondary);
			userParams
					.setAlreadyAddedEmailSecondaryNotActive((ArrayList<String>) userService
							.findAllNotActivatedEmailByUserId(userId));
			userParams.setCurrency(user.getCurrency());
			mav.addObject("userParameters", userParams);

			SessionHelper.setSaveAlreadyAddedEmailSecondary(session,
					saveAlreadyAddedEmailSecondary);
			SessionHelper.setSaveEmailPrimary(session, saveEmailPrimary);
			return mav;
		} else
			return new ModelAndView("redirect:/account/login.html");
	}

	@SuppressWarnings({ "unchecked", "deprecation" })
	@RequestMapping(value = { "/profile" }, method = RequestMethod.POST)
	public ModelAndView postProfile(HttpSession session,
			HttpServletRequest httprequest,
			final RedirectAttributes redirectAttributes,
			@ModelAttribute @Valid UserParameters userParams,
			BindingResult result) throws UserNotFoundException {

		if (!SessionHelper.isLoggedIn(session)) {
			return new ModelAndView("redirect:/account/login.html");
		}
		if (result.hasErrors()) {
			ModelAndView mavError = new ModelAndView("account/profile");
			mavError.addObject("userParameters", userParams);
			return mavError;
		} else {
			LOGGER.info(userParams.getAddEmailSecondary());
			User user = userService.findById(SessionHelper
					.getSaveUserId(session));
			// check password if equal("")
			if (!userParams.getNewPassword().equals(DEFAULT_PASSWORD)
					&& !userParams.getCurrentPassword()
							.equals(DEFAULT_PASSWORD)) {
				user.setPassword(EncryptDecrypt.encryptMD5(userParams
						.getNewPassword()));
			}
			// set Phone Number
			user.setPhone(userParams.getPhone().trim());
			// check date format
			if ("".equals(userParams.getDateOfBirth().trim())) {
				user.setDateOfBirth(null);
			} else {
				Date birth;
				try {
					// set DOB
					birth = new SimpleDateFormat("yyyy-MM-dd").parse(userParams
							.getDateOfBirth().trim());
					user.setDateOfBirth(birth);
				} catch (ParseException e) {
					LOGGER.info("Parse Exception", e);
				}

			}
			user.setFirstName(userParams.getFirstName().trim());
			user.setLastName(userParams.getLastName().trim());
			user.setGender(Integer.parseInt(userParams.getGender().trim()));

			String[] currency = new String[10];
			currency = userParams.getCurrency().split("-");
			user.setCurrency(currency[0].trim());

			userService.update(user);

			SessionHelper.setUser(session, user); // set new user and currency
													// code back session

			boolean checkIfSwitchEmailToSecondaryAndDelete = false;

			List<String> saveAlreadyAddedEmailSecondary = SessionHelper
					.getSaveAlreadyAddedEmailSecondary(session);
			String saveEmailPrimary = SessionHelper
					.getSaveEmailPrimary(session);
			// switch primary email
			if (!userParams.getPrimaryEmail().equals(saveEmailPrimary)
					&& saveAlreadyAddedEmailSecondary.contains(userParams
							.getPrimaryEmail())) {
				try {
					checkIfSwitchEmailToSecondaryAndDelete = true;
					if (userEmailService.swithPrimaryToSecondaryEmail(
							user.getId(), userParams.getPrimaryEmail())) {
						UserEmail userEmail = userEmailService
								.findByEmailString(userParams.getPrimaryEmail());
						if (userEmail != null) {
							SessionHelper.setUserEmail(session, userEmail);
						}
					} else {
						String messages = "Please active "
								+ userParams.getPrimaryEmail()
								+ " before switch to default email.";
						return new ModelAndView("account/profile", "message",
								messages);
					}
				} catch (UserEmailNotFoundException e) {
					LOGGER.info("User Email Not Found", e);
				}

			}

			// delete added email secondary
			if (userParams.getAlreadyAddedEmailSecondary() != null) {
				List<String> deleteEmail = new ArrayList<String>();
				deleteEmail = saveAlreadyAddedEmailSecondary;

				deleteEmail.removeAll(userParams
						.getAlreadyAddedEmailSecondary());
				// check primary email switch before delete
				if (userParams.getAlreadyAddedEmailSecondary().contains(
						saveEmailPrimary)) {
					// set to secondary
					deleteEmail.remove(saveEmailPrimary);

					try {
						userEmailService.swithPrimaryToSecondaryEmail(
								user.getId(), saveEmailPrimary);
					} catch (UserEmailNotFoundException e) {
						LOGGER.info("User Email Not Found", e);
					}

				}

				if (deleteEmail.contains(userParams.getPrimaryEmail())) {
					deleteEmail.remove(userParams.getPrimaryEmail());
				}

				for (int i = 0; i < deleteEmail.size(); i++) {
					try {
						userEmailService.deleteUserEmailByUserIdAndEmail(
								user.getId(), deleteEmail.get(i));
					} catch (UserEmailNotFoundException e) {
						LOGGER.info("User Email Not Found", e);
					}
				}

			} else {
				saveAlreadyAddedEmailSecondary.remove(userParams
						.getPrimaryEmail());
				if (checkIfSwitchEmailToSecondaryAndDelete) {
					saveAlreadyAddedEmailSecondary.add(saveEmailPrimary);
				}
				for (int i = 0; i < saveAlreadyAddedEmailSecondary.size(); i++) {
					try {
						userEmailService.deleteUserEmailByUserIdAndEmail(
								user.getId(),
								saveAlreadyAddedEmailSecondary.get(i));
					} catch (UserEmailNotFoundException e) {
						LOGGER.info("Cant find User email: ", e);
					}
				}
			}

			// save new add email
			String collectAddEmail = "";
			List<String> addEmailSecondary = userParams.getAddEmailSecondary();
			ModelAndView mv = new ModelAndView("redirect:/account/profile.html");
			if (addEmailSecondary != null) {
				UserEmail userEmail = new UserEmail();

				// delete duplicate email
				@SuppressWarnings({ "rawtypes" })
				Set h = new HashSet(addEmailSecondary);
				addEmailSecondary.clear();
				addEmailSecondary.addAll(h);

				for (int i = 0; i < addEmailSecondary.size(); i++) {
					userEmail.setIdUser(user.getId());
					userEmail.setEmail(addEmailSecondary.get(i));
					userEmail.setActive(false);
					userEmail.setPrimary(false);
					userEmail.setUser(user);
					userEmail.setRegistrationDate(new Date().getTime() / 1000L
							+ "");
					UserEmail saveUserEmail = userEmailService
							.create(userEmail);
					collectAddEmail += userEmail.getEmail() + " and ";

					// send active email
					String activation_link = Utils
							.getURLWithContextPath(httprequest)
							+ "/account/activation_account_email.html";
					String param = null;
					try {
						param = EncryptDecrypt.encryptDES(saveUserEmail.getId()
								+ "|" + (new Date()).getTime());

						activation_link += "?param=" + URLEncoder.encode(param);
					} catch (Exception e) {
						LOGGER.info("error", e);
					}

					if (emailService.sendActivateEmail(userEmail.getEmail(),
							env.getRequiredProperty(PROPERTY_PRODUCT_NAME),
							activation_link)) {
						userEmailService.setActivationAccountLinkParam(saveUserEmail, param);
					}

				}
				userParams.setAddEmailSecondary(null);
				LOGGER.info(userParams.getAddEmailSecondary());
			}
			if (!collectAddEmail.equals("")) {
				collectAddEmail = (String) collectAddEmail.subSequence(0,
						collectAddEmail.length() - 4);
				redirectAttributes.addFlashAttribute(
						"success",
						env.getProperty(PROPERTY_EMAIL_HAS_SEND_PARAM).replace(
								"xxx", collectAddEmail));
				return mv;
			}
			redirectAttributes.addFlashAttribute("success",
					env.getProperty(PROPERTY_UPDATE_PROFILE_SUCCESS));
			return mv;
		}
	}

	@RequestMapping(value = { "/reset_password_request" }, method = RequestMethod.GET)
	public ModelAndView getResetPasswordRequest() {
		return new ModelAndView("account/reset_password_request");
	}

	@SuppressWarnings("deprecation")
	@RequestMapping(value = { "/reset_password_request" }, method = RequestMethod.POST)
	public ModelAndView postResetPasswordRequest(
			@ModelAttribute @Valid ResetPasswordRequestParameters resetPasswordRequestParameters,
			BindingResult result, HttpServletRequest httprequest,
			Map<String, Object> model) {
		LOGGER.info("DO HERE : reset_password_request !!!!!!!!!!");
		ModelAndView mavError = new ModelAndView(
				"account/reset_password_request");
		User user = null;
		// check email
		UserEmail userEmail = userEmailService
				.findByEmailString(resetPasswordRequestParameters
						.getUserEmail());
		if (userEmail == null) {
			return mavError;
		} else {
			user = userEmail.getUser();
			if (user == null)
				return mavError;
		}

		if (result.hasErrors()) {
			return mavError;
		} else {
			String reset_link = Utils.getURLWithContextPath(httprequest)
					+ "/account/reset_password.html";
			String param = null;
			try {
				param = EncryptDecrypt.encryptDES(user.getId() + "|"
						+ (new Date()).getTime());
				reset_link += "?param=" + URLEncoder.encode(param);
			} catch (Exception e) {
				LOGGER.info("error", e);
			}
			if (emailService.sendResetLink(resetPasswordRequestParameters.getUserEmail(),
					reset_link)) {
				userService.setResetPasswordLinkParam(user, param);
				ModelAndView mav = new ModelAndView("flight/search");
				mav.addObject("success",
						env.getRequiredProperty(PROPERTY_EMAIL_HAS_SEND));
				mav.addObject("success",
						env.getRequiredProperty(PROPERTY_SEND_EMAIL_SUCCESS));
				return mav;
			} else
				return new ModelAndView("activation/message", "message",
						env.getRequiredProperty(PROPERTY_EMAIL_HASNT_SEND));
		}
	}

	@RequestMapping(value = { "/reset_password" }, method = RequestMethod.GET)
	public ModelAndView getResetPassword(
			@RequestParam(value = "param", required = false) String param,
			Map<String, Object> model,
			final RedirectAttributes redirectAttributes, HttpSession session) {
		ModelAndView mav = new ModelAndView("account/reset_password");
		boolean resetRequestAccepted = false;
		SessionHelper.setSaveLinkParam(session, param); // in encrypted

		try {
			String decryptedParam = EncryptDecrypt.decryptDES(param); // in
																		// decrypted
			String[] str = new String[2];
			int index = decryptedParam.indexOf("|");
			str[0] = decryptedParam.substring(0, index);
			str[1] = decryptedParam.substring(index + 1,
					decryptedParam.length());

			int saveId = Integer.parseInt(str[0]);
			SessionHelper.setSaveUserId(session, saveId);

			User user = userService.findById(saveId);
			if (user != null) {
				if (!param.equals(user.getResetLinkParam())) { // if param not
																// same
					ModelAndView mavError = new ModelAndView(
							"redirect:/flight/search.html");
					redirectAttributes
							.addFlashAttribute(
									"message",
									env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
					return mavError;
				} else {
					Date now = new Date();
					long delta = (now.getTime() - Long.parseLong(str[1])) / 1000; // /3600000
					if (delta > Integer.parseInt(env
							.getRequiredProperty(PROPERTY_PASSWORD_RESET_TIME))) {
						// remove request
						userService.setResetPasswordLinkParam(userService.findById(saveId),
								null);
						ModelAndView mavError = new ModelAndView(
								"redirect:/flight/search.html");
						redirectAttributes
								.addFlashAttribute(
										"message",
										env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
						return mavError;
					} else {
						resetRequestAccepted = true;
						String notify = user.getFirstName() + " "
								+ user.getLastName() + ", "
								+ userService.getPrimaryEmail(user.getId())
								+ "!";
						mav.addObject("notify", notify.replace("null", "")
								.replace(" ,", ""));
					}
				}
			} else {
				userService.setResetPasswordLinkParam(userService.findById(saveId), null);
				ModelAndView mavError = new ModelAndView(
						"redirect:/flight/search.html");
				redirectAttributes
						.addFlashAttribute(
								"message",
								env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
				return mavError;
			}
		} catch (Exception e) {
			LOGGER.info("error", e);
			ModelAndView mavError = new ModelAndView(
					"redirect:/flight/search.html");
			redirectAttributes
					.addFlashAttribute(
							"message",
							env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
			return mavError;
		}

		SessionHelper.setResetRequestAccepted(session, resetRequestAccepted);
		return mav;
	}

	@SuppressWarnings("deprecation")
	@RequestMapping(value = { "/reset_password" }, method = RequestMethod.POST)
	public ModelAndView postResetPassword(
			@ModelAttribute @Valid ResetPasswordParameters resetPasswordParams,
			BindingResult result, final RedirectAttributes redirectAttributes,
			HttpServletRequest httprequest, Map<String, Object> model,
			HttpSession session) {
		ModelAndView mav = new ModelAndView(
				"redirect:/account/reset_password.html?param="
						+ URLEncoder.encode(SessionHelper
								.getSaveLinkParam(session)));
		LOGGER.info("DO HERE : reset_password !!!!!!!!!!");
		String message = "";
		if (result.hasErrors()) {
			LOGGER.error(result.getAllErrors().toString());
			return mav;
		}
		if (!SessionHelper.isResetRequestAccepted(session)) {
			message = env.getProperty(PROPERTY_REQUEST_NOT_ACCEPTED);
		} else {
			try {
				User user = userService.findById(SessionHelper
						.getSaveUserId(session));
				userService.setResetPasswordLinkParam(user, null); // remove request after
														// use
				userService.updatePassword(user.getId(), EncryptDecrypt
						.encryptMD5(resetPasswordParams.getNewPassword()));

				emailService.sendResetSuccess(userService.getPrimaryEmail(user.getId()),
						Utils.getURLWithContextPath(httprequest)
								+ "/account/login.html");
				ModelAndView mavSuccess = new ModelAndView(
						"redirect:/account/login.html");
				redirectAttributes.addFlashAttribute("success",
						env.getProperty(PROPERTY_REQUEST_ACCEPTED));
				return mavSuccess;
			} catch (UserNotFoundException e) {
				LOGGER.info("User Not Found", e);
				message = env.getProperty(PROPERTY_USER_NOT_FOUND);
			}
		}
		redirectAttributes.addFlashAttribute("message", message);
		return mav;
	}


	/***** Signup Controller *****/
	@RequestMapping(value = { "/signup" }, method = RequestMethod.GET)
	public ModelAndView getSignup() {
		return new ModelAndView("account/signup");
	}

	@SuppressWarnings("deprecation")
	@RequestMapping(value = "/signup", method = RequestMethod.POST)
	public ModelAndView postSignup(
			@ModelAttribute @Valid SignupParameters params,
			BindingResult result, RedirectAttributes redirectAttribute,
			HttpSession session, HttpServletRequest httprequest,
			Map<String, Object> model) throws Exception {

		if (result.hasErrors()) {
			LOGGER.info(result.getFieldErrors().toString());
			ModelAndView mav = new ModelAndView("account/signup");
			if (result.getFieldErrorCount("userEmail") == 0) {
				mav.addObject("userEmail", params.getUserEmail());
			}
			return mav;
		}

		String pass_encrypted = EncryptDecrypt.encryptMD5(params.getPassword());

		User user = new User();
		user.setPassword(pass_encrypted);
		user.setCurrency("USD");
		user.setSendViaEmail(true);
		user.setSendViaEmail(false);

		User savedUser = userService.create(user);
		UserEmail userEmail = new UserEmail();
		userEmail.setIdUser(savedUser.getId());
		userEmail.setEmail(params.getUserEmail());
		userEmail.setActive(false); // set to false, require activate account by
									// email
		userEmail.setPrimary(true);
		userEmail.setUser(savedUser);
		userEmail.setRegistrationDate(new Date().getTime() / 1000L + "");
		UserEmail saveUserEmail = userEmailService.create(userEmail);

		// send activate email
		String activation_link = Utils.getURLWithContextPath(httprequest)
				+ "/account/activation_account_email.html";
		String param = null;
		try {
			param = EncryptDecrypt.encryptDES(saveUserEmail.getId() + "|"
					+ (new Date()).getTime());

			activation_link += "?param=" + URLEncoder.encode(param);
		} catch (Exception e) {
			LOGGER.info("Error", e);
		}
		if (emailService.sendActivateEmail(params.getUserEmail(),
				env.getRequiredProperty(PROPERTY_PRODUCT_NAME), activation_link)) {
			userEmailService.setActivationAccountLinkParam(saveUserEmail, param);
			return new ModelAndView("redirect:/flight/search.html", "success",
					env.getProperty(PROPERTY_CREATE_ACCOUNT_SUCCESS) + "<br>"
							+ env.getRequiredProperty(PROPERTY_EMAIL_HAS_SEND));

		} else {
			return new ModelAndView("activation/message", "message",
					env.getRequiredProperty(PROPERTY_EMAIL_HASNT_SEND));
		}
	}

	@RequestMapping(value = { "/activation_account_email" }, method = RequestMethod.GET)
	public ModelAndView getActivationAccountEmail(
			@RequestParam(value = "param", required = false) String param,
			final RedirectAttributes redirectAttributes,
			Map<String, Object> model) {
		ModelAndView mav = new ModelAndView("redirect:/flight/search.html"); // error
		String save_param = param; // in encrypted
		try {
			param = EncryptDecrypt.decryptDES(param); // in decrypted
			LOGGER.info("decrypted param=" + param);
			String[] str = new String[2];
			int index = param.indexOf("|");
			str[0] = param.substring(0, index);
			str[1] = param.substring(index + 1, param.length());
			LOGGER.info("userEmail_id=" + str[0]);
			LOGGER.info("datetime=" + str[1]);
			UserEmail userEmail = userEmailService.findById(Integer
					.parseInt(str[0]));
			if (userEmail != null) {
				if (!save_param.equals(userEmail.getActivationLinkParam())) { // if
																				// param
																				// not
																				// the
																				// same
					redirectAttributes
							.addFlashAttribute(
									"message",
									env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
				} else {
					Date now = new Date();
					long delta = (now.getTime() - Long.parseLong(str[1])) / 1000; // /3600000
					LOGGER.info("delta value time: " + delta / 1000);
					if (delta > Integer.parseInt(env
							.getRequiredProperty(PROPERTY_ACTIVATION_EXPIRED))) {
						redirectAttributes
								.addFlashAttribute(
										"message",
										env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
					} else {
						userEmail.setActive(true);
						userEmail.setActivationLinkParam(null);
						userEmailService.update(userEmail);
						// activate successful
						ModelAndView mavSuccess = new ModelAndView(
								"redirect:/account/login.html");
						redirectAttributes.addFlashAttribute(
								"success",
								env.getRequiredProperty(
										PROPERTY_EMAIL_ACTIVED_PARAM).replace(
										"xxx",
										"<strong>" + userEmail.getEmail()
												+ "</strong>"));
						return mavSuccess;
					}
				}
				userEmailService.setActivationAccountLinkParam(userEmail, null); // remove
																// request
			} else {
				redirectAttributes
						.addFlashAttribute(
								"message",
								env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
			}
		} catch (Exception e) {
			LOGGER.info("Error", e);
			redirectAttributes
					.addFlashAttribute(
							"message",
							env.getRequiredProperty(PROPERTY_LINK_INCORRECT_OR_EXPIRED));
		}
		return mav;
	}

	@RequestMapping(value = { "/activation_error" }, method = RequestMethod.GET)
	public ModelAndView getActivationError(
			@RequestParam(value = "user_email", required = false) String user_email,
			Map<String, Object> model) {

		model.put("user_email", user_email);
		model.put(
				"message",
				env.getRequiredProperty(PROPERTY_EMAIL_DIDNT_ACTIVE)
						+ "<br><br>"
						+ env.getRequiredProperty(PROPERTY_EMAIL_DIDNT_RECEIVE));
		return new ModelAndView("activation/message");

	}

	@SuppressWarnings("deprecation")
	@RequestMapping(value = { "/activation_error" }, method = RequestMethod.POST)
	public ModelAndView postActivationError(
			RedirectAttributes redirectAttribute,
			HttpServletRequest httprequest, Map<String, Object> model,
			HttpSession session) {

		UserEmail userEmail = userEmailService.findById(SessionHelper
				.getSaveUserEmailId(session));

		// send activate email
		String activation_link = Utils.getURLWithContextPath(httprequest)
				+ "/account/activation_account_email.html";
		String param = null;
		try {
			param = EncryptDecrypt.encryptDES(userEmail.getId() + "|"
					+ (new Date()).getTime());
			activation_link += "?param=" + URLEncoder.encode(param);
		} catch (Exception e) {
			LOGGER.info("activation link ", e);
		}

		redirectAttribute.addFlashAttribute("user_email", userEmail.getEmail());
		if (emailService.sendActivateEmail(userEmail.getEmail(),
				env.getRequiredProperty(PROPERTY_PRODUCT_NAME), activation_link)) {
			userEmailService.setActivationAccountLinkParam(userEmail, param);
			ModelAndView mavSuccess = new ModelAndView(
					"redirect:/flight/search.html");
			redirectAttribute.addFlashAttribute("success",
					env.getRequiredProperty(PROPERTY_EMAIL_HAS_SEND));
			return mavSuccess;
		} else {
			ModelAndView mavError = new ModelAndView(
					"redirect:/activation/message.html");
			redirectAttribute.addFlashAttribute("message",
					env.getRequiredProperty(PROPERTY_EMAIL_HASNT_SEND));
			return mavError;
		}
	}

}
